package simulacao.cenario;

import javafx.animation.Interpolator;
import javafx.animation.transition.FadeTransition;
import javafx.scene.CustomNode;
import javafx.scene.image.Image;
import simulacao.modelo.pistas.Pista;
import simulacao.util.Util;
import javafx.animation.Timeline;
import javafx.animation.transition.OrientationType;
import javafx.animation.transition.PathTransition;
import javafx.scene.Group;
import javafx.scene.Node;
import java.lang.Integer;
import simulacao.SimulationCore;
import simulacao.modelo.veiculos.Veiculo;
import simulacao.util.SaidaPersonalizada.*;
import javafx.util.Math;

public class Cenario extends CustomNode {

    /*******************************************************

    Atributos referentes a modelagem da simulação

     ********************************************************/
    public-init var quantidadeCarros: Integer;
    public-init var quantidadeCaminhoes: Integer;
    public-read var veiculos: Veiculo[];
    public var veiculoSelecionado: Veiculo;
    public var veiculoRecemAdicionado: Veiculo;
    public-init var pista: Pista;
    /*******************************************************

    Atributos utilizados para adequacao ao framework

     ********************************************************/
    public-init var icone: Image;
    public-init var idCenario: Integer;
    public-read var listAnimacao: PathTransition[];

    public function adicionarVeiculoAleatorioAposInicioDaSimulacao() {

        var animacao : PathTransition;

        if (Util.random(10) < 7) {
                quantidadeCarros++;
                animacao = adicionarVeiculo(Veiculo.TIPO_CARRO, 10);
        } else {
            quantidadeCaminhoes++;
            animacao = adicionarVeiculo(Veiculo.TIPO_CAMINHAO, 10);
        }

        animacao.playFromStart();
    }
    
    function adicionarVeiculo(tipoNovoVeiculo: Integer, quantidadeDeLoopsParaFicarVisivel : Integer) : PathTransition {

        var idNovoVeiculo: Integer = recuperaMaiorIdDeVeiculo() + 1;

        escreverSaida("Adicionando Veiculo: {idNovoVeiculo} - tipo: {if(tipoNovoVeiculo == Veiculo.TIPO_CARRO) "Carro" else "Caminhão"}");

        var novoVeiculo: Veiculo = Veiculo {
                    faixaDeRodagemAtual: Util.random(pista.QUANTIDADE_DE_FAIXAS)
                    pista: pista
                    idVeiculo: idNovoVeiculo
                    tipoVeiculo: tipoNovoVeiculo
                    indiceDeAgressividade: Util.random(10)
                    idVeiculoSobreposto: -2
                    quantidadeLoopsParaFicarVisivel: quantidadeDeLoopsParaFicarVisivel
                    visible: false;
                }

        var animacao = PathTransition {
                    node: novoVeiculo
                    path: bind pista.faixasDeRodagemAnimadas[novoVeiculo.faixaDeRodagemAtual];
                    orientation: OrientationType.ORTHOGONAL_TO_TANGENT
                    interpolator: Interpolator.LINEAR
                    duration: 10000ms
                    repeatCount: Timeline.INDEFINITE
                    autoReverse: false
                    rate: bind novoVeiculo.rateRelativaVelocidadeAtual
                }


        novoVeiculo.animacaoDoVeiculo = animacao;
        insert novoVeiculo into veiculos;
        insert animacao into listAnimacao;

        SimulationCore.vetorDeAntecipacaoDeColisao.limparColisao(idNovoVeiculo);
//        animacao.playFromStart();

        escreverSaida("Veiculo adicionado: {idNovoVeiculo} - tipo: {if(tipoNovoVeiculo == Veiculo.TIPO_CARRO) "Carro" else "Caminhão"}");

        return animacao;

    }

    public function removerVeiculoSelecionado() {

        for (veiculoAnimado in listAnimacao where (veiculoAnimado.node as Veiculo).idVeiculo == veiculoSelecionado.idVeiculo) {
            delete  listAnimacao[indexof veiculoAnimado];
        }

        if (veiculoSelecionado.tipoVeiculo == Veiculo.TIPO_CARRO) {
            quantidadeCarros--;
        } else {
            quantidadeCaminhoes--;
        }
        SimulationCore.vetorDeAntecipacaoDeColisao.limparColisao(veiculoSelecionado.idVeiculo);
        delete veiculoSelecionado from veiculos;
        veiculoSelecionado = null;
    }

    function recuperaMaiorIdDeVeiculo() : Integer {
        var maiorId : Integer = -1;
        for (veiculo in veiculos){ maiorId = Math.max(maiorId, veiculo.idVeiculo)}
        return maiorId;
    }

    public override function create(): Node {

        for (i in [0..quantidadeCarros + quantidadeCaminhoes - 1]){
            var tipoVeiculo = if (i < quantidadeCarros) Veiculo.TIPO_CARRO else Veiculo.TIPO_CAMINHAO;
            adicionarVeiculo(tipoVeiculo, (i * 5) + 10);
        }
        return Group {content: bind [pista, veiculos]}
    }

// Funções de controle
    public function play() {
        for (animacao in listAnimacao)
            if ((animacao.node as Veiculo).velocidadeAtual > 0.001)
                animacao.play();
    }

    public function pause() {
        for (animacao in listAnimacao)
            if ((animacao.node as Veiculo).velocidadeAtual > 0.001)
                animacao.pause();
    }

    public function reset() {
        for (animacao in listAnimacao) {
            animacao.stop();
            (animacao.node as Veiculo).inicializaComValoresDefault();
        }
    }

    public function playFromStart() {
        for (animacao in listAnimacao)
            animacao.playFromStart();
    }

// Efeitos de transição
    var fadein = FadeTransition {
                node: this
                fromValue: bind this.opacity
                toValue: 1
                duration: 2s
                interpolator: Interpolator.EASEOUT
            };

    var fadeout = FadeTransition {
                node: this
                fromValue: bind this.opacity
                toValue: 0
                duration: 2s
                interpolator: Interpolator.EASEOUT
            };

    public function fadeIn() {
        fadeout.stop();
        fadein.play();
    }

    public function fadeOut() {
        fadein.stop();
        fadeout.play();
    }
}
